package cn.tnar.yunpark.careyes.nbiot;

import cn.tnar.yunpark.careyes.BCCTool;
import cn.tnar.yunpark.careyes.CarEyesUtil;
import cn.tnar.yunpark.careyes.nbiot.model.HeartBeat;
import cn.tnar.yunpark.careyes.nbiot.model.NBAckMessage;
import cn.tnar.yunpark.careyes.nbiot.model.NBStatus;
import cn.tnar.yunpark.careyes.nbiot.model.Time;
import cn.tnar.yunpark.util.ByteTool;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.List;


/**
 * author : CaineZhu
 * date   : 2017/12/22
 * desc   : CarEyesTCPMessageDecoder
 */


public class CarEyesNBMessageDecoder extends MessageToMessageDecoder<DatagramPacket> {

    Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    public int findHeader(ByteBuf buf) {
        int len = buf.readerIndex() + buf.readableBytes();
        int index = -1;
        for (int i = buf.readerIndex(); i < len; i++) {
            byte b = buf.getByte(i);
            if (b == CarEyesUtil.HEADER[0]) {
                int tmp = i + 1;
                if (tmp < len) {
                    byte b1 = buf.getByte(tmp);
                    if (b1 == CarEyesUtil.HEADER[1]) {
                        index = i;
                        break;
                    }
                }
            }
        }
        return index;
    }

    @Override
    protected void decode(ChannelHandlerContext context, DatagramPacket datagramPacket, List<Object> list) throws Exception {

        ByteBuf byteBuf = datagramPacket.content();
        int readable = byteBuf.readableBytes();
        if (readable <= 5) {
            logger.info("readableBytes not enough");
            return;
        }
        int index = findHeader(byteBuf);
        if (index == -1) {
            logger.warn("header not found!");
            return;
        }

        byteBuf.readerIndex(index);//设置游标

        byte type = byteBuf.getByte(2);
        int len = byteBuf.getByte(3) & 0xFF;
        ByteBuf buf = Unpooled.buffer(len);
        try {
            byteBuf.readBytes(buf);
            byte[] source = new byte[buf.readableBytes()];
            buf.getBytes(0,source);
            logger.info("receiver len:{} data:{}", len,ByteTool.bytes2String(source));
            boolean crcValida = BCCTool.crcValidation(buf);
            if (!crcValida) {
                logger.warn("crc validation false.");
                return;
            }
            switch (type) {
                case CarEyesUtil.STATUS: {//上报状态
                    if (len < 0x28) {
                        return;
                    }
                    NBStatus record = NBStatus.parse(buf);
                    list.add(record);
                    context.writeAndFlush(new DatagramPacket(
                            Unpooled.copiedBuffer(statusResponse(record)), datagramPacket.sender())).sync();
                }
                break;
                case CarEyesUtil.HEART_BEAT: {
                    if (len < 0x27) {
                        return;
                    }
                    HeartBeat record = HeartBeat.parse(buf);
                    list.add(record);
                    context.writeAndFlush(new DatagramPacket(
                            Unpooled.copiedBuffer(heartbeatResponse(record)), datagramPacket.sender())).sync();
                }
                break;
                case CarEyesUtil.TIME: {
                    if (len < 0x18) {
                        return;
                    }
                    Time record = Time.parse(buf);
                    context.writeAndFlush(new DatagramPacket(
                            Unpooled.copiedBuffer(timeResponse(record)), datagramPacket.sender())).sync();
                }
                break;
                default:
//                NBStatus record = NBStatus.parse(byteBuf);
//                list.add(record);
//                context.writeAndFlush(new DatagramPacket(
//                        Unpooled.copiedBuffer(statusResponse(record)), datagramPacket.sender())).sync();
            }
        }finally{
            buf.release();
        }
    }

    //0x72回复
    public ByteBuf statusResponse(NBStatus record) {
        NBAckMessage ack = new NBAckMessage();
        ack.setLen(0x18);
        ack.setType(0x92);
        ack.setDeviceType(0x00);
        return ack.toArray(record.getSensorIdBytes(), record.getParkIdBytes(), record.getCity(), record.getArea(), record.getSequence());
    }

    //0x73回复
    public ByteBuf heartbeatResponse(HeartBeat record) {
        ByteBuf buf = Unpooled.buffer(0x18);
        buf.writeByte(0xff);
        buf.writeByte(0xfe);
        buf.writeByte(0x93);
        buf.writeByte(0x18);
        buf.writeByte(record.getDeviceType());
        buf.writeBytes(record.getSensorIdBytes());
        buf.writeByte(0x88);
        buf.writeByte(record.getCity());
        buf.writeByte(record.getArea());
        buf.writeBytes(record.getParkIdBytes());
        buf.writeByte(0x88);
        buf.writeByte(0x00);
        buf.writeByte(record.getSequence());
        buf.writeByte(BCCTool.bccCalc(buf));
        buf.writeByte(0xab);
        buf.writeByte(0xaa);
        return buf;
    }

    //0x74回复
    public ByteBuf timeResponse(Time record) {
        Calendar calendar = Calendar.getInstance();
        ByteBuf buf = Unpooled.buffer(0x22);
        buf.writeByte(0xff);
        buf.writeByte(0xfe);
        buf.writeByte(0x94);
        buf.writeByte(0x22);
        buf.writeByte(record.getDeviceType());
        buf.writeBytes(record.getSensorIdBytes());
        buf.writeByte(0x88);
        buf.writeByte(record.getCity());
        buf.writeByte(record.getArea());
        buf.writeBytes(record.getParkIdBytes());
        buf.writeByte(0x88);
        buf.writeByte(0x88);
        buf.writeByte(0x88);
        buf.writeByte(0x88);
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.YEAR) - 2000));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.MONTH) + 1));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.DAY_OF_MONTH)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.HOUR_OF_DAY)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.MINUTE)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.SECOND)));
        buf.writeByte(0x88);
        buf.writeByte(0x00);
        buf.writeByte(record.getSequence());
        buf.writeByte(BCCTool.bccCalc(buf));
        buf.writeByte(0xab);
        buf.writeByte(0xaa);
        return buf;
    }
}
